package com.wswy.wzcx.utils;

import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import com.che.libcommon.utils.RxHelper;
import com.che.libcommon.utils.optional.Optional;
import com.facebook.common.memory.PooledByteBuffer;
import com.facebook.common.memory.PooledByteBufferInputStream;
import com.facebook.common.memory.PooledByteStreams;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.util.StreamUtil;
import com.facebook.common.util.UriUtil;
import com.facebook.datasource.DataSource;
import com.facebook.datasource.DataSources;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.common.Priority;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.core.ImagePipelineFactory;
import com.facebook.imagepipeline.image.CloseableBitmap;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.nativecode.Bitmaps;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imageutils.BitmapUtil;
import io.reactivex.Single;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Callable;


public class FrescoUtils {

  private static final String TAG = "FrescoUtils";

  public static ImageRequest fetchImageRequest(String url,int width,int height){
    Uri uri = null;
    if (url!= null && url.startsWith("/")){
      uri = UriUtil.getUriForFile(new File(url));
    }else {
      uri = UriUtil.parseUriOrNull(url);
    }
    ImageRequestBuilder requestBuilder = ImageRequestBuilder.newBuilderWithSource(uri);
    if(width !=0 && height != 0){
      requestBuilder = requestBuilder.setResizeOptions(ResizeOptions.forDimensions(width, height));
    }

    return requestBuilder.build();
  }

  public static boolean preLoadBitmap(String url,int width,int height){
    ImageRequest imageRequest = fetchImageRequest(url, width,height);
    if(Fresco.getImagePipeline().isInBitmapMemoryCache(imageRequest)){
      return true;
    }

    DataSource<Void> voidDataSource = null;
    try {
      voidDataSource = Fresco.getImagePipeline()
          .prefetchToBitmapCache(imageRequest, null);
      DataSources.waitForFinalResult(voidDataSource);
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      if(voidDataSource != null){
        voidDataSource.close();
      }
    }

    Log.e(TAG, "preLoadBitmap --> "+Fresco.getImagePipeline().isInBitmapMemoryCache(imageRequest));

    return Fresco.getImagePipeline().isInBitmapMemoryCache(imageRequest);
  }

  public static void downloadImage(String url){
    ImageRequest imageRequest = fetchImageRequest(url, 0,0);

    DataSource<CloseableReference<PooledByteBuffer>> dataSource = null;
    CloseableReference<PooledByteBuffer> closeableImageRef = null;

    try {
      dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchEncodedImage(imageRequest, null);

      closeableImageRef = DataSources.waitForFinalResult(dataSource);
      if (closeableImageRef != null && closeableImageRef.isValid() &&
          closeableImageRef.get() != null) {
      }
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      CloseableReference.closeSafely(closeableImageRef);
      closeableImageRef = null;
      if(dataSource != null){
        dataSource.close();
      }
    }
  }

  public static void asyncDownloadImage(String url){
    ImageRequest imageRequest = fetchImageRequest(url, 0, 0);
    ImagePipelineFactory.getInstance().getImagePipeline().prefetchToDiskCache(imageRequest,null);

  }

  public static Bitmap syncFetchBitmap(String url,int width,int height){

    ImageRequest imageRequest = fetchImageRequest(url, width, height);
    DataSource<CloseableReference<CloseableImage>> dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchDecodedImage(imageRequest, null);
    CloseableReference<CloseableImage> closeableImageRef = null;

    try {
      closeableImageRef = DataSources.waitForFinalResult(dataSource);
      if (closeableImageRef != null &&
          closeableImageRef.get() instanceof CloseableBitmap) {
         return  ((CloseableBitmap) closeableImageRef.get()).getUnderlyingBitmap();
      }

    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      CloseableReference.closeSafely(closeableImageRef);
      closeableImageRef = null;
      if(dataSource != null){
        dataSource.close();
      }
    }

    return null;
  }


  public static Bitmap syncFetchBitmap(ImageRequest imageRequest){

    DataSource<CloseableReference<CloseableImage>> dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchDecodedImage(imageRequest, null);
    CloseableReference<CloseableImage> closeableImageRef = null;

    try {
      closeableImageRef = DataSources.waitForFinalResult(dataSource);
      if (closeableImageRef != null &&
          closeableImageRef.get() instanceof CloseableBitmap) {
        Bitmap srcBitmap = ((CloseableBitmap) closeableImageRef.get()).getUnderlyingBitmap();

        return srcBitmap.copy(srcBitmap.getConfig(),false);
      }

    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      CloseableReference.closeSafely(closeableImageRef);
      closeableImageRef = null;
      if(dataSource != null){
        dataSource.close();
      }
    }

    return null;
  }


  public static Single<Optional<Bitmap>> loadBitmap(final ImageRequest request){
    return Single.fromCallable(new Callable<Optional<Bitmap>>() {
      @Override
      public Optional<Bitmap> call() throws Exception {

        Bitmap bitmap = syncFetchBitmap(request);


        return Optional.ofNullable(bitmap);
      }
    }).compose(RxHelper.<Optional<Bitmap>>io2main());
  }


  public static byte[] syncFetchBytes(String url,int width,int height){

    ImageRequest imageRequest = fetchImageRequest(url, width, height);
    DataSource<CloseableReference<PooledByteBuffer>> dataSource = null;
    CloseableReference<PooledByteBuffer> closeableImageRef = null;

    PooledByteBufferInputStream stream = null;
    try {
      dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchEncodedImage(imageRequest, null);

      closeableImageRef = DataSources.waitForFinalResult(dataSource);
      if (closeableImageRef != null && closeableImageRef.isValid() &&
          closeableImageRef.get() != null) {

        PooledByteBuffer pooledByteBuffer = closeableImageRef.get();
        stream = new PooledByteBufferInputStream(pooledByteBuffer);

        byte[] bytesFromStream = StreamUtil.getBytesFromStream(stream);
        Log.e(TAG, "syncFetchBytes --> "+bytesFromStream.length);
        return bytesFromStream;
      }

    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      try {
        if(stream != null) {
          stream.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }

      CloseableReference.closeSafely(closeableImageRef);
      closeableImageRef = null;

      if(dataSource != null){
        dataSource.close();
      }
    }

    return null;
  }


  public static byte[] syncWXFetchBitmap(String url,int width,int height){

    ImageRequest imageRequest = fetchImageRequest(url, width, height);
    DataSource<CloseableReference<PooledByteBuffer>> dataSource = null;
    CloseableReference<PooledByteBuffer> closeableImageRef = null;

    PooledByteBufferInputStream stream = null;
    try {
      dataSource = ImagePipelineFactory.getInstance().getImagePipeline().fetchEncodedImage(imageRequest, null);

      closeableImageRef = DataSources.waitForFinalResult(dataSource);
      if (closeableImageRef != null && closeableImageRef.isValid() &&
          closeableImageRef.get() != null) {

        PooledByteBuffer pooledByteBuffer = closeableImageRef.get();
        stream = new PooledByteBufferInputStream(pooledByteBuffer);

        byte[] bytesFromStream = StreamUtil.getBytesFromStream(stream);
        //微信分享icon不能大于32k
        if(bytesFromStream.length > 32768){
          Bitmap bitmap = BitmapFactory.decodeByteArray(bytesFromStream, 0, bytesFromStream.length);
          ByteArrayOutputStream output = new ByteArrayOutputStream();
          bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
          int options = 90;
          while (output.toByteArray().length > 32768 && options != 10) {
            output.reset();
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, output);
            options -= 10;
          }
          return output.toByteArray();
        }
        return bytesFromStream;
      }

    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }finally {
      try {
        if(stream != null) {
          stream.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }

      CloseableReference.closeSafely(closeableImageRef);
      closeableImageRef = null;

      if(dataSource != null){
        dataSource.close();
      }
    }

    return null;
  }


  public static void removeCache(Uri uri){
    Fresco.getImagePipeline().evictFromCache(uri);
  }

}
